import React, { useEffect, useState } from 'react';
import { Button, Popover, Icon, Modal, Radio, Progress, Upload, message, Tooltip } from 'antd';
import cn from 'classnames';
import ResourceImg from '../../images/slave.png';
import './index.less';
import { CancelToken } from 'axios';
import _ from 'lodash';
import moment from 'moment';
import PropTypes from 'prop-types';
import arrowDownImg from '../../images/arrow-down.svg';
import {
  cancelUpgrade,
  resourceInfo,
  uploadClanPackage,
  getClusterAutoUpdate,
  clusterAutoUpdate,
  clusterUpgrade,
  getUpgradeUpdate
} from '@api/update';
import UpgradingImg from '../../images/upgrading.png';
import '../../index.less';
const prefixCls = 'resourc-update';
const RadioGroup = Radio.Group;
const typeDist = {
  single: '',
  slave: '扫描节点',
  master: '管理节点'
};
const radioStyle = {
  display: 'block',
  height: '30px',
  lineHeight: '30px'
};

const getSize = bytes => {
  if (bytes < 0) {
    return '0B';
  }
  const units = ['B', 'K', 'M', 'G'];
  for (let level = 0; level < units.length; level++) {
    if (bytes < Math.pow(1024, level + 1) || level === units.length - 1) {
      const unit = units[level];
      const prefix = parseInt((100 * bytes) / Math.pow(1024, level), 10) / 100;
      return `${prefix}${unit}`;
    }
  }
};

const getTime = rawSecond => {
  const second = parseInt(rawSecond % 60, 10).toString();
  const minutes = parseInt((rawSecond % (60 * 60)) / 60, 10).toString();
  const hours = parseInt(rawSecond / (60 * 60), 10).toString();
  return [
    hours.length >= 2 ? hours : `00${hours}`.slice(-2),
    `00${minutes}`.slice(-2),
    `00${second}`.slice(-2)
  ].join(':');
};

const ResourceUpdate = props => {
  const { lastSystemUpgrade, deviceId, enableSensitivePage, nodesProgressList, cert } = props;
  const [lastUpgrade, setLastUpgrade] = useState('');
  const [version, setVersion] = useState('');
  const [uploadModalVisible, setUploadModalVisible] = useState(false);
  const [saveLoading, setSaveLoading] = useState(false);
  const [uploadingPackage, setUploadingPackage] = useState(false);
  const [modeVisible, setModeVisible] = useState(false);
  const [mode, setMode] = useState('auto');
  const [packageFile, setPackageFile] = useState();
  const [percent, setPercent] = useState(0);
  const [bytesPerSecond, setBytesPerSecond] = useState(0);
  const [remainUploadSeconds, setRemainUploadSeconds] = useState(0);
  const [verifyModalVisible, setVerifyModalVisible] = useState(false);
  const [verify, setVerify] = useState();
  const [pkginfo, setPkginfo] = useState();
  const [cancel, setCancel] = useState({ fun: '' });
  const [lastRecordLoaded, setLastRecordLoaded] = useState(0);
  const [lastRecordTime, setLastRecordTime] = useState(0);
  const [loaded, setLoaded] = useState();
  const [progressTotal, setProgressTotal] = useState();
  const [pollTimer, setPollTimer] = useState(null);
  const [resourceUpdateNode, setResourceUpdateNode] = useState(true);
  const [sysmgVisible, setSysmgVisible] = useState(false);
  const [node, setNode] = useState(null);
  const [uploadErrorMsg, setUploadErrorMsg] = useState('');
  const content = (
    <div>
      <b>自动升级：</b>请确保您的网络环境能访问外网。
      <br />
      <br />
      <b>手动升级：</b>如您的服务器不能访问外网，请选择手动升级。
    </div>
  );
  const now = Number(_.get(cert, 'now', 0));
  const expired = Number(_.get(cert, 'expiry_time', 0)) * 1000 < now;
  // 判断更新(升级)方式
  const getUpdateWay = () => {
    const now = Number(_.get(cert, 'now', 0));
    const isExpired = Number(_.get(cert, 'expiry_time', 0)) * 1000 < now;

    if (isExpired) {
      return '授权证书已过期，暂时无法升级';
    }
    if (mode === 'auto') {
      return '自动升级，每10分钟访问一次升级服务器（如您的服务器不能访问外网，请选择手动升级）';
    } else {
      return '手动升级';
    }
  };

  // 资源库信息
  const getResourceInfo = async () => {
    await resourceInfo()
      .then(r => {
        const { version, isAuto, lastUpgradedAt } = _.get(r, 'data.data');
        setVersion(version || '暂无版本');
        setLastUpgrade(
          lastUpgradedAt ? moment(lastUpgradedAt).format('YYYY-MM-DD HH:mm:ss') : null
        );
        setMode(isAuto === 'ACTIVE' ? 'auto' : 'manual');
      })
      .catch(e => {
        message.error(e.message);
      });
    let res = await getClusterAutoUpdate({ update_type: 'resource' });
    setMode(_.get(res, 'data.data.auto_upgrade_status') === 'inactive' ? 'manual' : 'auto');
  };

  // 集群请求的升级
  const getUpgradeState = () => {
    getUpgradeUpdate().then(res => {
      const data = _.get(res, 'data', []);
      let item = data.find(r => r.role === 'master' && r.update_type === 'resource');
      if (!item) {
        return;
      }
      if (status === 'success') {
        getResourceInfo();
        window.clearInterval(pollTimer);
      }
    });
  };

  const pollStatus = () => {
    setPollTimer(window.setInterval(getUpgradeState, 4000));
  };

  // 上传
  const uploadUpdate = () => {
    const body = new FormData();
    body.append('file', packageFile);
    let config = {
      onUploadProgress: progressEvent => {
        let loadedE = progressEvent.loaded;
        setLoaded(loadedE);
        let total = progressEvent.total;
        setProgressTotal(total);
        let percent = ((loadedE / total) * 100) | 0;
        let now = Date.now();
        setLastRecordTime(now);
        setLastRecordLoaded(loadedE);
        setPercent(percent);
      },
      cancelToken: new CancelToken(cancel => {
        setCancel({ fun: cancel });
      })
    };
    setPercent(0);
    setUploadingPackage(true);
    setLastRecordLoaded(0);
    setLastRecordTime(Date.now());
    let api = uploadClanPackage;
    body.append('update_type', 'resource');
    api(body, config)
      .then(res => {
        setVerify(true);
        setVerifyModalVisible(true);
        setPercent(100);
        setPkginfo(_.get(res, 'data.data.result.pkginfo', {}));
        setUploadingPackage(false);
        setUploadModalVisible(false);
        pollStatus();
      })
      .catch(e => {
        if (e.message) {
          setUploadErrorMsg('升级包无效');
          setUploadingPackage(false);
          setUploadModalVisible(false);
          setVerifyModalVisible(true);
          setVerify(false);
        } else {
          // 手动取消
          message.error('取消上传');
          setUploadingPackage(false);
        }
      });
  };

  const postUpgrade = () => {
    let body = { batchId: _.get(pkginfo, 'batchId', '') };
    let api = clusterUpgrade;
    body = { update_type: 'resource', vision: pkginfo.version };

    api(body)
      .then(() => {
        message.success('正在升级！');
        setVerifyModalVisible(false);
      })
      .catch(e => {
        message.error(e.message);
      });
  };

  const postCancel = () => {
    if (!_.get(pkginfo, 'batchId')) {
      setVerifyModalVisible(false);
      return;
    }

    cancelUpgrade({ batchId: _.get(pkginfo, 'batchId', '') })
      .then(() => {
        message.success('取消成功');
        setVerifyModalVisible(false);
      })
      .catch(err => {
        message.error(err.message);
      });
  };

  const verifyModalProps = verify
    ? {
        onOk: postUpgrade,
        onCancel: postCancel,
        okText: '开始更新',
        cancelText: '暂不更新'
      }
    : {
        footer: [
          <Button
            type="primary"
            key="0"
            onClick={() => {
              setVerifyModalVisible(false), setPackageFile(null);
            }}
          >
            关闭
          </Button>
        ]
      };

  const onRadioChange = e => {
    const value = e.target.value;
    if (value === 'manual') {
      setMode('manual');
      return;
    }
    setMode('auto');
  };

  const beforeUpload = packageFile => {
    setPackageFile(packageFile);
    return false;
  };

  const cancelUpload = () => {
    cancel.fun();
    setPackageFile(null);
  };

  const onSave = () => {
    setSaveLoading(true);
    let api = clusterAutoUpdate;
    let body = { auto: mode === 'auto' ? 'start' : 'stop', update_type: 'resource' };
    api(body)
      .then(() => {
        message.success('保存升级方式成功');
        setSaveLoading(false);
        setModeVisible(false);
      })
      .catch(() => {
        message.error('保存升级方式失败');
        setSaveLoading(false);
      })
      .finally(() => {
        getResourceInfo();
      });
  };

  useEffect(() => {
    if (lastRecordTime && lastRecordLoaded) {
      setBytesPerSecond((1000 * (loaded - lastRecordLoaded)) / (Date.now() - lastRecordTime));
    }
  }, [loaded]);

  useEffect(() => {
    if (bytesPerSecond) {
      setRemainUploadSeconds((progressTotal - loaded) / bytesPerSecond);
    }
  }, [bytesPerSecond]);

  useEffect(() => {
    if (packageFile) {
      uploadUpdate();
    }
  }, [packageFile]);

  useEffect(() => {
    if (verify) {
      setVerifyModalVisible(true);
    }
  }, [verify]);

  useEffect(() => {
    const node = _.find(nodesProgressList, i => i.ip === version);
    let item = nodesProgressList.find(r => r.status === 'updating');
    if (!node) {
      if (item) {
        if (item?.expire * 1000 > Date.now()) {
          setNode(item);
          setResourceUpdateNode(false);
          return;
        }
      }
    }
    setResourceUpdateNode(true);
  }, [nodesProgressList]);

  useEffect(() => {
    getResourceInfo();
    window.clearInterval(pollTimer);
  }, []);

  const displayStatus = () => {
    return !resourceUpdateNode;
  };
  const formatStr = _.get(pkginfo, 'changeLog', '-').replace('\\n', '<br>');
  const formatStrContent = () => {
    let content = _.get(pkginfo, 'content', []);
    let contentStr = '';

    content.map(r => {
      contentStr += `<div>${r}</div>`;
    });
    return contentStr;
  };
  return (
    <div className={`${prefixCls}-wrapper-`}>
      <div className={prefixCls}>
        <div className={`${prefixCls}-page-title`}>资源库升级</div>
        <div className={`${prefixCls}-top`} style={{ height: 120 }}>
          <div className="left">
            <img src={ResourceImg} className="icon" />
            <Tooltip
              visible={sysmgVisible && displayStatus()}
              title={`${typeDist[(node?.role)]}${node?.ip}正在进行${
                node?.update_type === 'sysmg' ? '系统' : '资源库'
              }升级，建议不要同时升级，请稍后重试`}
              disabled={true}
              style={{ background: 'red' }}
            >
              <span>
                <Button
                  type="primary"
                  disabled={displayStatus()}
                  onMouseOver={() => setSysmgVisible(true)}
                  onMouseOut={() => setSysmgVisible(false)}
                  onClick={() => {
                    setUploadModalVisible(true);
                    setPackageFile(null);
                    setUploadingPackage(false);
                  }}
                >
                  上传升级包
                </Button>
              </span>
            </Tooltip>
          </div>
          <div className="right">
            <div className={`${prefixCls}-item`}>
              <div className={`${prefixCls}-item-title`}>当前版本</div>
              <div className={`${prefixCls}-item-detail`}>{version}</div>
            </div>
            <div className={`${prefixCls}-item`}>
              <div className={`${prefixCls}-item-title`}>最近更新时间</div>
              {/* 资源库更新时间为空时，使用系统升级更新时间 */}
              <div className={`${prefixCls}-item-detail`}>
                {lastUpgrade ? lastUpgrade : lastSystemUpgrade}
              </div>
            </div>
            <div className={`${prefixCls}-item`}>
              <Popover placement="topLeft" content={content} overlayStyle={{ width: 420 }}>
                <div className={`${prefixCls}-item-title`}>
                  更新方式&nbsp;
                  <Icon type="info-circle" />
                </div>
              </Popover>
              <div className={`${prefixCls}-item-detail`}>
                <span>{getUpdateWay()}</span>
                <span
                  // className={cn({ 'be-color': expired })}
                  style={{
                    color: expired ? 'rgba(0, 0, 0, 0.25)' : '#1890ff',
                    cursor: expired ? 'not-allowed' : 'pointer',
                    marginLeft: 16
                  }}
                  onClick={() => !expired && setModeVisible(true)}
                  loading={saveLoading}
                >
                  编辑升级方式
                </span>
              </div>
            </div>
          </div>
        </div>

        <div style={{ marginTop: 40 }}>
          <div>注：手动升级需要您上传升级文件，升级文件获取方式</div>
          {enableSensitivePage && (
            <div className={`${prefixCls}-manual-intro`}>
              <div className={`${prefixCls}-manual-intro-step`}>
                <div className={`${prefixCls}-manual-intro-step-num`}>1</div>
                <div className={`${prefixCls}-manual-intro-step-arrow`}>
                  <img src={arrowDownImg} alt="" />
                </div>
                <div className={`${prefixCls}-manual-intro-step-num`}>2</div>
                <div className={`${prefixCls}-manual-intro-step-arrow`}>
                  <img src={arrowDownImg} alt="" />
                </div>
                <div className={`${prefixCls}-manual-intro-step-num`}>3</div>
              </div>
              <div>
                <div className={`${prefixCls}-manual-intro-msg`}>
                  先访问
                  <a
                    href="https://update.knownsec.com/datapkgs"
                    target="_blank"
                    rel="noopener noreferrer"
                  >
                    https://update.knownsec.com/datapkgs
                  </a>
                </div>
                <div className={`${prefixCls}-manual-intro-msg`}>
                  输入License Key：<span style={{ color: '#0b6fd6' }}>{deviceId}&nbsp;</span>
                  进行登录验证，成功登录后下载大于当前版本
                  <span style={{ color: '#0b6fd6' }}>&nbsp;{version}&nbsp;</span>的最新版本升级文件
                </div>
                <div className={`${prefixCls}-manual-intro-msg`}>
                  在此页面点击”上传升级包“按钮，将资源库升级至您想要的版本。
                </div>
              </div>
            </div>
          )}
        </div>
      </div>

      <Modal
        maskClosable={false}
        className={cn(`${prefixCls}-upload-pkg-modal`, 'no-header-bottom-lines', 'padding-24')}
        visible={uploadModalVisible}
        title={uploadingPackage ? '安装包上传中' : '上传安装包'}
        footer={null}
        onCancel={() => setUploadModalVisible(false)}
      >
        {!uploadingPackage && (
          <Upload.Dragger accept=".pkg" beforeUpload={beforeUpload} fileList={[]}>
            <div className="upload-wrapper">
              <Icon type="upload" className="icon" width={32} height={32} />
              <div className="desc">
                <span>点击或拖拽至此处上传</span>
                <span>仅支持 *.pkg 文件</span>
              </div>
            </div>
          </Upload.Dragger>
        )}
        {packageFile && (
          <div className="update-info">
            <div className="top">
              <Icon type="link" />
              {_.get(packageFile, 'name', '-')}&nbsp;({getSize(_.get(packageFile, 'size', 0))})
            </div>
            <div className="bottom">
              <Progress percent={percent} showInfo={false} />
              <span className="speed">{`${getSize(bytesPerSecond)}/s`}</span>
              <span className="remain">{getTime(remainUploadSeconds)}</span>
              <span className="remove" onClick={cancelUpload}>
                删除
              </span>
            </div>
          </div>
        )}
      </Modal>

      <Modal
        maskClosable={false}
        className={cn('mode-change-modal', 'no-header-bottom-lines', 'bottom-center', 'padding-24')}
        visible={modeVisible}
        title={'编辑升级方式'}
        confirmLoading={saveLoading}
        onOk={onSave}
        onCancel={() => setModeVisible(false)}
      >
        <RadioGroup onChange={onRadioChange} value={mode}>
          <Radio value={'auto'} style={radioStyle}>
            自动升级,每10分钟访问一次升级服务器
          </Radio>
          <Radio value={'manual'} style={radioStyle}>
            手动升级
          </Radio>
        </RadioGroup>
      </Modal>

      <Modal
        maskClosable={false}
        className={cn(
          `${prefixCls}-verify`,
          'no-header-bottom-lines',
          'bottom-center',
          'padding-24'
        )}
        closable={false}
        visible={verifyModalVisible}
        {...verifyModalProps}
      >
        {pkginfo ? (
          <div className="pkginfo">
            <div className="icon">
              <img src={UpgradingImg} />
            </div>

            <div className="version" dangerouslySetInnerHTML={{ __html: formatStr }} />
            <div className="version" dangerouslySetInnerHTML={{ __html: formatStrContent() }} />
            <div className="version">{_.get(pkginfo, 'version', '-')}&nbsp;升级</div>
          </div>
        ) : (
          <div>
            <p>升级包上传失败!</p>
            <p style={{ marginBottom: 0 }}>{uploadErrorMsg} </p>
          </div>
        )}
      </Modal>
    </div>
  );
};

ResourceUpdate.propTypes = {
  lastSystemUpgrade: PropTypes.string,
  enableSensitivePage: PropTypes,
  cert: PropTypes.object,
  deviceId: PropTypes,
  nodesProgressList: PropTypes.array
};

export default ResourceUpdate;
